package com.lgc.javathread.threadLocalTest.test2;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 1. Thread类中有一个成员变量属于ThreadLocalMap类(一个定义在ThreadLocal类中的内部类)，
 * 它是一个Map，他的key是ThreadLocal实例对象。
 * 2. 当为ThreadLocal类的对象set值时，首先获得当前线程的ThreadLocalMap类属性，
 * 然后以ThreadLocal类的对象为key，设定value。get值时则类似。
 * 3. ThreadLocal变量的活动范围为某线程，是该线程“专有的，独自霸占”的，对该变量的所有操作均由该线程完成！
 * 也就是说，ThreadLocal 不是用来解决共享对象的多线程访问的竞争问题的，
 * 因为ThreadLocal.set() 到线程中的对象是该线程自己使用的对象，其他线程是不需要访问的，也访问不到的。
 * 当线程终止后，这些值会作为垃圾回收。
 * 4. 由ThreadLocal的工作原理决定了：每个线程独自拥有一个变量，并非是共享的
 */
public class Son implements Cloneable {
    public static void main(String[] args) {

        //***** ThreadLocalMap的key是ThreadLocal类的实例对象，value为用户的值，并不是网上大多数的例子key是线程的名字或者标识。
        Son son=new Son();
        System.out.println(son);

        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                ThreadLocal<Son> threadLocal = new ThreadLocal<>();
                System.out.println(threadLocal);

                threadLocal.set(son); //set()
                System.out.println(threadLocal.get());//get()
                threadLocal.remove();//remove()

                try {
                    /*也就是如果把一个共享的对象直接保存到ThreadLocal中，
                    那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身，还是有并发访问问题。
                    所以要在保存到ThreadLocal之前，通过克隆或者new来创建新的对象，然后再进行保存。*/
                    threadLocal.set((Son) son.clone());
                    System.out.println(threadLocal.get());

                } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
                }

                System.out.println(threadLocal);
            }
        });
        t.start();
    }
}
